/* $Id: PrintfFormat.java 127 2011-08-25 14:22:27Z altdotua@gmail.com $ */

package alt.djudge.frontend.server.utils;

//
//(c) 2000 Sun Microsystems, Inc.
//ALL RIGHTS RESERVED
//
//License Grant-
//
//
//Permission to use, copy, modify, and distribute this Software and its 
//documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is 
//hereby granted.  
//
//This Software is provided "AS IS".  All express warranties, including any 
//implied warranty of merchantability, satisfactory quality, fitness for a 
//particular purpose, or non-infringement, are disclaimed, except to the extent 
//that such disclaimers are held to be legally invalid.
//
//You acknowledge that Software is not designed, licensed or intended for use in 
//the design, construction, operation or maintenance of any nuclear facility 
//("High Risk Activities").  Sun disclaims any express or implied warranty of 
//fitness for such uses.  
//
//Please refer to the file http://www.sun.com/policies/trademarks/ for further 
//important trademark information and to 
//http://java.sun.com/nav/business/index.html for further important licensing 
//information for the Java Technology.
//

import java.util.Enumeration;
import java.util.Vector;
import java.util.Locale;
import java.text.DecimalFormatSymbols;

/**
* PrintfFormat allows the formatting of an array of
* objects embedded within a string.  Primitive types
* must be passed using wrapper types.  The formatting
* is controlled by a control string.
*<p>
* A control string is a Java string that contains a
* control specification.  The control specification
* starts at the first percent sign (%) in the string,
* provided that this percent sign
*<ol>
*<li>is not escaped protected by a matching % or is
* not an escape % character,
*<li>is not at the end of the format string, and
*<li>precedes a sequence of characters that parses as
* a valid control specification.
*</ol>
*</p><p>
* A control specification usually takes the form:
*<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
*                { [hlL] }+ [idfgGoxXeEcs]
*</pre>
* There are variants of this basic form that are
* discussed below.</p>
*<p>
* The format is composed of zero or more directives
* defined as follows:
*<ul>
*<li>ordinary characters, which are simply copied to
* the output stream;
*<li>escape sequences, which represent non-graphic
* characters; and
*<li>conversion specifications,  each of which
* results in the fetching of zero or more arguments.
*</ul></p>
*<p>
* The results are undefined if there are insufficient
* arguments for the format.  Usually an unchecked
* exception will be thrown.  If the format is
* exhausted while arguments remain, the excess
* arguments are evaluated but are otherwise ignored.
* In format strings containing the % form of
* conversion specifications, each argument in the
* argument list is used exactly once.</p>
* <p>
* Conversions can be applied to the <code>n</code>th
* argument after the format in the argument list,
* rather than to the next unused argument.  In this
* case, the conversion characer % is replaced by the
* sequence %<code>n</code>$, where <code>n</code> is
* a decimal integer giving the position of the
* argument in the argument list.</p>
* <p>
* In format strings containing the %<code>n</code>$
* form of conversion specifications, each argument
* in the argument list is used exactly once.</p>
*
*<h4>Escape Sequences</h4>
*<p>
* The following table lists escape sequences and
* associated actions on display devices capable of
* the action.
*<table>
*<tr><th align=left>Sequence</th>
*    <th align=left>Name</th>
*    <th align=left>Description</th></tr>
*<tr><td>\\</td><td>backlash</td><td>None.
*</td></tr>
*<tr><td>\a</td><td>alert</td><td>Attempts to alert
*          the user through audible or visible
*          notification.
*</td></tr>
*<tr><td>\b</td><td>backspace</td><td>Moves the
*          printing position to one column before
*          the current position, unless the
*          current position is the start of a line.
*</td></tr>
*<tr><td>\f</td><td>form-feed</td><td>Moves the
*          printing position to the initial 
*          printing position of the next logical
*          page.
*</td></tr>
*<tr><td>\n</td><td>newline</td><td>Moves the
*          printing position to the start of the
*          next line.
*</td></tr>
*<tr><td>\r</td><td>carriage-return</td><td>Moves
*          the printing position to the start of
*          the current line.
*</td></tr>
*<tr><td>\t</td><td>tab</td><td>Moves the printing
*          position to the next implementation-
*          defined horizontal tab position.
*</td></tr>
*<tr><td>\v</td><td>vertical-tab</td><td>Moves the
*          printing position to the start of the
*          next implementation-defined vertical
*          tab position.
*</td></tr>
*</table></p>
*<h4>Conversion Specifications</h4>
*<p>
* Each conversion specification is introduced by
* the percent sign character (%).  After the character
* %, the following appear in sequence:</p>
*<p>
* Zero or more flags (in any order), which modify the
* meaning of the conversion specification.</p>
*<p>
* An optional minimum field width.  If the converted
* value has fewer characters than the field width, it
* will be padded with spaces by default on the left;
* t will be padded on the right, if the left-
* adjustment flag (-), described below, is given to
* the field width.  The field width takes the form
* of a decimal integer.  If the conversion character
* is s, the field width is the the minimum number of
* characters to be printed.</p>
*<p>
* An optional precision that gives the minumum number
* of digits to appear for the d, i, o, x or X
* conversions (the field is padded with leading
* zeros); the number of digits to appear after the
* radix character for the e, E, and f conversions,
* the maximum number of significant digits for the g
* and G conversions; or the maximum number of
* characters to be written from a string is s and S
* conversions.  The precision takes the form of an
* optional decimal digit string, where a null digit
* string is treated as 0.  If a precision appears
* with a c conversion character the precision is
* ignored.
* </p>
*<p>
* An optional h specifies that a following d, i, o,
* x, or X conversion character applies to a type 
* short argument (the argument will be promoted
* according to the integral promotions and its value
* converted to type short before printing).</p>
*<p>
* An optional l (ell) specifies that a following
* d, i, o, x, or X conversion character applies to a
* type long argument.</p>
*<p>
* A field width or precision may be indicated by an
* asterisk (*) instead of a digit string.  In this
* case, an integer argument supplised the field width
* precision.  The argument that is actually converted
* is not fetched until the conversion letter is seen,
* so the the arguments specifying field width or
* precision must appear before the argument (if any)
* to be converted.  If the precision argument is
* negative, it will be changed to zero.  A negative
* field width argument is taken as a - flag, followed
* by a positive field width.</p>
* <p>
* In format strings containing the %<code>n</code>$
* form of a conversion specification, a field width
* or precision may be indicated by the sequence
* *<code>m</code>$, where m is a decimal integer
* giving the position in the argument list (after the
* format argument) of an integer argument containing
* the field width or precision.</p>
* <p>
* The format can contain either numbered argument
* specifications (that is, %<code>n</code>$ and
* *<code>m</code>$), or unnumbered argument
* specifications (that is % and *), but normally not
* both.  The only exception to this is that %% can
* be mixed with the %<code>n</code>$ form.  The
* results of mixing numbered and unnumbered argument
* specifications in a format string are undefined.</p>
*
*<h4>Flag Characters</h4>
*<p>
* The flags and their meanings are:</p>
*<dl>
* <dt>'<dd> integer portion of the result of a
*      decimal conversion (%i, %d, %f, %g, or %G) will
*      be formatted with thousands' grouping
*      characters.  For other conversions the flag
*      is ignored.  The non-monetary grouping
*      character is used.
* <dt>-<dd> result of the conversion is left-justified
*      within the field.  (It will be right-justified
*      if this flag is not specified).</td></tr>
* <dt>+<dd> result of a signed conversion always
*      begins with a sign (+ or -).  (It will begin
*      with a sign only when a negative value is
*      converted if this flag is not specified.)
* <dt>&lt;space&gt;<dd> If the first character of a
*      signed conversion is not a sign, a space
*      character will be placed before the result.
*      This means that if the space character and +
*      flags both appear, the space flag will be
*      ignored.
* <dt>#<dd> value is to be converted to an alternative
*      form.  For c, d, i, and s conversions, the flag
*      has no effect.  For o conversion, it increases
*      the precision to force the first digit of the
*      result to be a zero.  For x or X conversion, a
*      non-zero result has 0x or 0X prefixed to it,
*      respectively.  For e, E, f, g, and G
*      conversions, the result always contains a radix
*      character, even if no digits follow the radix
*      character (normally, a decimal point appears in
*      the result of these conversions only if a digit
*      follows it).  For g and G conversions, trailing
*      zeros will not be removed from the result as
*      they normally are.
* <dt>0<dd> d, i, o, x, X, e, E, f, g, and G
*      conversions, leading zeros (following any
*      indication of sign or base) are used to pad to
*      the field width;  no space padding is
*      performed.  If the 0 and - flags both appear,
*      the 0 flag is ignored.  For d, i, o, x, and X
*      conversions, if a precision is specified, the
*      0 flag will be ignored. For c conversions,
*      the flag is ignored.
*</dl>
*
*<h4>Conversion Characters</h4>
*<p>
* Each conversion character results in fetching zero
* or more arguments.  The results are undefined if
* there are insufficient arguments for the format.
* Usually, an unchecked exception will be thrown.
* If the format is exhausted while arguments remain,
* the excess arguments are ignored.</p>
*
*<p>
* The conversion characters and their meanings are:
*</p>
*<dl>
* <dt>d,i<dd>The int argument is converted to a
*        signed decimal in the style [-]dddd.  The
*        precision specifies the minimum number of
*        digits to appear;  if the value being
*        converted can be represented in fewer
*        digits, it will be expanded with leading
*        zeros.  The default precision is 1.  The
*        result of converting 0 with an explicit
*        precision of 0 is no characters.
* <dt>o<dd> The int argument is converted to unsigned
*        octal format in the style ddddd.  The
*        precision specifies the minimum number of
*        digits to appear;  if the value being
*        converted can be represented in fewer
*        digits, it will be expanded with leading
*        zeros.  The default precision is 1.  The
*        result of converting 0 with an explicit
*        precision of 0 is no characters.
* <dt>x<dd> The int argument is converted to unsigned
*        hexadecimal format in the style dddd;  the
*        letters abcdef are used.  The precision
*        specifies the minimum numberof digits to
*        appear; if the value being converted can be
*        represented in fewer digits, it will be
*        expanded with leading zeros.  The default
*        precision is 1.  The result of converting 0
*        with an explicit precision of 0 is no
*        characters.
* <dt>X<dd> Behaves the same as the x conversion
*        character except that letters ABCDEF are
*        used instead of abcdef.
* <dt>f<dd> The floating point number argument is
*        written in decimal notation in the style
*        [-]ddd.ddd, where the number of digits after
*        the radix character (shown here as a decimal
*        point) is equal to the precision
*        specification.  A Locale is used to determine
*        the radix character to use in this format.
*        If the precision is omitted from the
*        argument, six digits are written after the
*        radix character;  if the precision is
*        explicitly 0 and the # flag is not specified,
*        no radix character appears.  If a radix
*        character appears, at least 1 digit appears
*        before it.  The value is rounded to the
*        appropriate number of digits.
* <dt>e,E<dd>The floating point number argument is
*        written in the style [-]d.ddde{+-}dd
*        (the symbols {+-} indicate either a plus or
*        minus sign), where there is one digit before
*        the radix character (shown here as a decimal
*        point) and the number of digits after it is
*        equal to the precision.  A Locale is used to
*        determine the radix character to use in this
*        format.  When the precision is missing, six
*        digits are written after the radix character;
*        if the precision is 0 and the # flag is not
*        specified, no radix character appears.  The
*        E conversion will produce a number with E
*        instead of e introducing the exponent.  The
*        exponent always contains at least two digits.
*        However, if the value to be written requires
*        an exponent greater than two digits,
*        additional exponent digits are written as
*        necessary.  The value is rounded to the
*        appropriate number of digits.
* <dt>g,G<dd>The floating point number argument is
*        written in style f or e (or in sytle E in the
*        case of a G conversion character), with the
*        precision specifying the number of
*        significant digits.  If the precision is
*        zero, it is taken as one.  The style used
*        depends on the value converted:  style e
*        (or E) will be used only if the exponent
*        resulting from the conversion is less than
*        -4 or greater than or equal to the precision.
*        Trailing zeros are removed from the result.
*        A radix character appears only if it is
*        followed by a digit.
* <dt>c,C<dd>The integer argument is converted to a
*        char and the result is written.
*
* <dt>s,S<dd>The argument is taken to be a string and
*        bytes from the string are written until the
*        end of the string or the number of bytes 
*        indicated by the precision specification of
*        the argument is reached.  If the precision
*        is omitted from the argument, it is taken to
*        be infinite, so all characters up to the end
*        of the string are written.
* <dt>%<dd>Write a % character;  no argument is
*        converted.
*</dl>
*<p>
* If a conversion specification does not match one of
* the above forms, an IllegalArgumentException is
* thrown and the instance of PrintfFormat is not
* created.</p>
*<p>
* If a floating point value is the internal
* representation for infinity, the output is
* [+]Infinity, where Infinity is either Infinity or
* Inf, depending on the desired output string length.
* Printing of the sign follows the rules described
* above.</p>
*<p>
* If a floating point value is the internal
* representation for "not-a-number," the output is
* [+]NaN.  Printing of the sign follows the rules
* described above.</p>
*<p>
* In no case does a non-existent or small field width
* cause truncation of a field;  if the result of a
* conversion is wider than the field width, the field
* is simply expanded to contain the conversion result.
*</p>
*<p>
* The behavior is like printf.  One exception is that
* the minimum number of exponent digits is 3 instead
* of 2 for e and E formats when the optional L is used
* before the e, E, g, or G conversion character.  The
* optional L does not imply conversion to a long long
* double. </p>
* <p>
* The biggest divergence from the C printf
* specification is in the use of 16 bit characters.
* This allows the handling of characters beyond the
* small ASCII character set and allows the utility to
* interoperate correctly with the rest of the Java
* runtime environment.</p>
*<p>
* Omissions from the C printf specification are
* numerous.  All the known omissions are present
* because Java never uses bytes to represent
* characters and does not have pointers:</p>
*<ul>
* <li>%c is the same as %C.
* <li>%s is the same as %S.
* <li>u, p, and n conversion characters. 
* <li>%ws format.
* <li>h modifier applied to an n conversion character.
* <li>l (ell) modifier applied to the c, n, or s
* conversion characters.
* <li>ll (ell ell) modifier to d, i, o, u, x, or X
* conversion characters.
* <li>ll (ell ell) modifier to an n conversion
* character.
* <li>c, C, d,i,o,u,x, and X conversion characters
* apply to Byte, Character, Short, Integer, Long
* types.
* <li>f, e, E, g, and G conversion characters apply
* to Float and Double types.
* <li>s and S conversion characters apply to String
* types.
* <li>All other reference types can be formatted
* using the s or S conversion characters only.
*</ul>
* <p>
* Most of this specification is quoted from the Unix
* man page for the sprintf utility.</p>
*
* @author Allan Jacobs
* @version 1
* Release 1: Initial release.
* Release 2: Asterisk field widths and precisions    
*            %n$ and *m$
*            Bug fixes
*              g format fix (2 digits in e form corrupt)
*              rounding in f format implemented
*              round up when digit not printed is 5
*              formatting of -0.0f
*              round up/down when last digits are 50000...
*/

@SuppressWarnings( { "unchecked", "unused", "rawtypes" })
public class PrintfFormat
{

	/**
	 * Constructs an array of control specifications possibly preceded,
	 * separated, or followed by ordinary strings. Control strings begin with
	 * unpaired percent signs. A pair of successive percent signs designates a
	 * single percent sign in the format.
	 * 
	 * @param fmtArg
	 *            Control string.
	 * @exception IllegalArgumentException
	 *                if the control string is null, zero length, or otherwise
	 *                malformed.
	 */
	public PrintfFormat(String fmtArg) throws IllegalArgumentException
	{
		this(Locale.getDefault(), fmtArg);
	}

	/**
	 * Constructs an array of control specifications possibly preceded,
	 * separated, or followed by ordinary strings. Control strings begin with
	 * unpaired percent signs. A pair of successive percent signs designates a
	 * single percent sign in the format.
	 * 
	 * @param fmtArg
	 *            Control string.
	 * @exception IllegalArgumentException
	 *                if the control string is null, zero length, or otherwise
	 *                malformed.
	 */
	public PrintfFormat(Locale locale, String fmtArg)
			throws IllegalArgumentException
	{
		dfs = new DecimalFormatSymbols(locale);
		int ePos = 0;
		ConversionSpecification sFmt = null;
		String unCS = this.nonControl(fmtArg, 0);
		if (unCS != null)
		{
			sFmt = new ConversionSpecification();
			sFmt.setLiteral(unCS);
			vFmt.addElement(sFmt);
		}
		while (cPos != -1 && cPos < fmtArg.length())
		{
			for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++)
			{
				char c = 0;
				c = fmtArg.charAt(ePos);
				if (c == 'i')
					break;
				if (c == 'd')
					break;
				if (c == 'f')
					break;
				if (c == 'g')
					break;
				if (c == 'G')
					break;
				if (c == 'o')
					break;
				if (c == 'x')
					break;
				if (c == 'X')
					break;
				if (c == 'e')
					break;
				if (c == 'E')
					break;
				if (c == 'c')
					break;
				if (c == 's')
					break;
				if (c == '%')
					break;
			}
			ePos = Math.min(ePos + 1, fmtArg.length());
			sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos));
			vFmt.addElement(sFmt);
			unCS = this.nonControl(fmtArg, ePos);
			if (unCS != null)
			{
				sFmt = new ConversionSpecification();
				sFmt.setLiteral(unCS);
				vFmt.addElement(sFmt);
			}
		}
	}

	/**
	 * Return a substring starting at <code>start</code> and ending at either
	 * the end of the String <code>s</code>, the next unpaired percent sign, or
	 * at the end of the String if the last character is a percent sign.
	 * 
	 * @param s
	 *            Control string.
	 * @param start
	 *            Position in the string <code>s</code> to begin looking for the
	 *            start of a control string.
	 * @return the substring from the start position to the beginning of the
	 *         control string.
	 */
	private String nonControl(String s, int start)
	{
		String ret = "";
		cPos = s.indexOf("%", start);
		if (cPos == -1)
			cPos = s.length();
		return s.substring(start, cPos);
	}

	/**
	 * Format an array of objects. Byte, Short, Integer, Long, Float, Double,
	 * and Character arguments are treated as wrappers for primitive types.
	 * 
	 * @param o
	 *            The array of objects to format.
	 * @return The formatted String.
	 */
	public String sprintf(Object[] o)
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		int i = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
			else
			{
				if (cs.isPositionalSpecification())
				{
					i = cs.getArgumentPosition() - 1;
					if (cs.isPositionalFieldWidth())
					{
						int ifw = cs.getArgumentPositionForFieldWidth() - 1;
						cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue());
					}
					if (cs.isPositionalPrecision())
					{
						int ipr = cs.getArgumentPositionForPrecision() - 1;
						cs.setPrecisionWithArg(((Integer) o[ipr]).intValue());
					}
				}
				else
				{
					if (cs.isVariableFieldWidth())
					{
						cs.setFieldWidthWithArg(((Integer) o[i]).intValue());
						i++;
					}
					if (cs.isVariablePrecision())
					{
						cs.setPrecisionWithArg(((Integer) o[i]).intValue());
						i++;
					}
				}
				if (o[i] instanceof Byte)
					sb.append(cs.internalsprintf(((Byte) o[i]).byteValue()));
				else if (o[i] instanceof Short)
					sb.append(cs.internalsprintf(((Short) o[i]).shortValue()));
				else if (o[i] instanceof Integer)
					sb.append(cs.internalsprintf(((Integer) o[i]).intValue()));
				else if (o[i] instanceof Long)
					sb.append(cs.internalsprintf(((Long) o[i]).longValue()));
				else if (o[i] instanceof Float)
					sb.append(cs.internalsprintf(((Float) o[i]).floatValue()));
				else if (o[i] instanceof Double)
					sb
							.append(cs.internalsprintf(((Double) o[i])
									.doubleValue()));
				else if (o[i] instanceof Character)
					sb.append(cs
							.internalsprintf(((Character) o[i]).charValue()));
				else if (o[i] instanceof String)
					sb.append(cs.internalsprintf((String) o[i]));
				else
					sb.append(cs.internalsprintf(o[i]));
				if (!cs.isPositionalSpecification())
					i++;
			}
		}
		return sb.toString();
	}

	/**
	 * Format nothing. Just use the control string.
	 * 
	 * @return the formatted String.
	 */
	public String sprintf()
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
		}
		return sb.toString();
	}

	/**
	 * Format an int.
	 * 
	 * @param x
	 *            The int to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is f, e, E, g, G, s, or S.
	 */
	public String sprintf(int x) throws IllegalArgumentException
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format an long.
	 * 
	 * @param x
	 *            The long to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is f, e, E, g, G, s, or S.
	 */
	public String sprintf(long x) throws IllegalArgumentException
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format a double.
	 * 
	 * @param x
	 *            The double to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is c, C, s, S, d, d, x, X, or
	 *                o.
	 */
	public String sprintf(double x) throws IllegalArgumentException
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format a String.
	 * 
	 * @param x
	 *            The String to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is neither s nor S.
	 */
	public String sprintf(String x) throws IllegalArgumentException
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format an Object. Convert wrapper types to their primitive equivalents
	 * and call the appropriate internal formatting method. Convert Strings
	 * using an internal formatting method for Strings. Otherwise use the
	 * default formatter (use toString).
	 * 
	 * @param x
	 *            the Object to format.
	 * @return the formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is inappropriate for
	 *                formatting an unwrapped value.
	 */
	public String sprintf(Object x) throws IllegalArgumentException
	{
		Enumeration e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while (e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if (c == '\0')
				sb.append(cs.getLiteral());
			else if (c == '%')
				sb.append("%");
			else
			{
				if (x instanceof Byte)
					sb.append(cs.internalsprintf(((Byte) x).byteValue()));
				else if (x instanceof Short)
					sb.append(cs.internalsprintf(((Short) x).shortValue()));
				else if (x instanceof Integer)
					sb.append(cs.internalsprintf(((Integer) x).intValue()));
				else if (x instanceof Long)
					sb.append(cs.internalsprintf(((Long) x).longValue()));
				else if (x instanceof Float)
					sb.append(cs.internalsprintf(((Float) x).floatValue()));
				else if (x instanceof Double)
					sb.append(cs.internalsprintf(((Double) x).doubleValue()));
				else if (x instanceof Character)
					sb.append(cs.internalsprintf(((Character) x).charValue()));
				else if (x instanceof String)
					sb.append(cs.internalsprintf((String) x));
				else
					sb.append(cs.internalsprintf(x));
			}
		}
		return sb.toString();
	}

	/**
	 *<p>
	 * ConversionSpecification allows the formatting of a single primitive or
	 * object embedded within a string. The formatting is controlled by a format
	 * string. Only one Java primitive or object can be formatted at a time.
	 *<p>
	 * A format string is a Java string that contains a control string. The
	 * control string starts at the first percent sign (%) in the string,
	 * provided that this percent sign
	 *<ol>
	 *<li>is not escaped protected by a matching % or is not an escape %
	 * character,
	 *<li>is not at the end of the format string, and
	 *<li>precedes a sequence of characters that parses as a valid control
	 * string.
	 *</ol>
	 *<p>
	 * A control string takes the form:
	 * 
	 * <pre>
	 * % ['-+ #0]* [0..9]* { . [0..9]* }+
	 *                { [hlL] }+ [idfgGoxXeEcs]
	 *</pre>
	 *<p>
	 * The behavior is like printf. One (hopefully the only) exception is that
	 * the minimum number of exponent digits is 3 instead of 2 for e and E
	 * formats when the optional L is used before the e, E, g, or G conversion
	 * character. The optional L does not imply conversion to a long long
	 * double.
	 */
	private class ConversionSpecification
	{

		/**
		 * Constructor. Used to prepare an instance to hold a literal, not a
		 * control string.
		 */
		ConversionSpecification()
		{
		}

		/**
		 * Constructor for a conversion specification. The argument must begin
		 * with a % and end with the conversion character for the conversion
		 * specification.
		 * 
		 * @param fmtArg
		 *            String specifying the conversion specification.
		 * @exception IllegalArgumentException
		 *                if the input string is null, zero length, or otherwise
		 *                malformed.
		 */
		ConversionSpecification(String fmtArg) throws IllegalArgumentException
		{
			if (fmtArg == null)
				throw new NullPointerException();
			if (fmtArg.length() == 0)
				throw new IllegalArgumentException(
						"Control strings must have positive" + " lengths.");
			if (fmtArg.charAt(0) == '%')
			{
				fmt = fmtArg;
				pos = 1;
				setArgPosition();
				setFlagCharacters();
				setFieldWidth();
				setPrecision();
				setOptionalHL();
				if (setConversionCharacter())
				{
					if (pos == fmtArg.length())
					{
						if (leadingZeros && leftJustify)
							leadingZeros = false;
						if (precisionSet && leadingZeros)
						{
							if (conversionCharacter == 'd'
									|| conversionCharacter == 'i'
									|| conversionCharacter == 'o'
									|| conversionCharacter == 'x')
							{
								leadingZeros = false;
							}
						}
					}
					else
						throw new IllegalArgumentException(
								"Malformed conversion specification=" + fmtArg);
				}
				else
					throw new IllegalArgumentException(
							"Malformed conversion specification=" + fmtArg);
			}
			else
				throw new IllegalArgumentException(
						"Control strings must begin with %.");
		}

		/**
		 * Set the String for this instance.
		 * 
		 * @param s
		 *            the String to store.
		 */
		void setLiteral(String s)
		{
			fmt = s;
		}

		/**
		 * Get the String for this instance. Translate any escape sequences.
		 * 
		 * @return s the stored String.
		 */
		String getLiteral()
		{
			StringBuffer sb = new StringBuffer();
			int i = 0;
			while (i < fmt.length())
			{
				if (fmt.charAt(i) == '\\')
				{
					i++;
					if (i < fmt.length())
					{
						char c = fmt.charAt(i);
						switch (c)
						{
						case 'a':
							sb.append((char) 0x07);
							break;
						case 'b':
							sb.append('\b');
							break;
						case 'f':
							sb.append('\f');
							break;
						case 'n':
							sb.append(System.getProperty("line.separator"));
							break;
						case 'r':
							sb.append('\r');
							break;
						case 't':
							sb.append('\t');
							break;
						case 'v':
							sb.append((char) 0x0b);
							break;
						case '\\':
							sb.append('\\');
							break;
						}
						i++;
					}
					else
						sb.append('\\');
				}
				else
					i++;
			}
			return fmt;
		}

		/**
		 * Get the conversion character that tells what type of control
		 * character this instance has.
		 * 
		 * @return the conversion character.
		 */
		char getConversionCharacter()
		{
			return conversionCharacter;
		}

		/**
		 * Check whether the specifier has a variable field width that is going
		 * to be set by an argument.
		 * 
		 * @return <code>true</code> if the conversion uses an * field width;
		 *         otherwise <code>false</code>.
		 */
		boolean isVariableFieldWidth()
		{
			return variableFieldWidth;
		}

		/**
		 * Set the field width with an argument. A negative field width is taken
		 * as a - flag followed by a positive field width.
		 * 
		 * @param fw
		 *            the field width.
		 */
		void setFieldWidthWithArg(int fw)
		{
			if (fw < 0)
				leftJustify = true;
			fieldWidthSet = true;
			fieldWidth = Math.abs(fw);
		}

		/**
		 * Check whether the specifier has a variable precision that is going to
		 * be set by an argument.
		 * 
		 * @return <code>true</code> if the conversion uses an * precision;
		 *         otherwise <code>false</code>.
		 */
		boolean isVariablePrecision()
		{
			return variablePrecision;
		}

		/**
		 * Set the precision with an argument. A negative precision will be
		 * changed to zero.
		 * 
		 * @param pr
		 *            the precision.
		 */
		void setPrecisionWithArg(int pr)
		{
			precisionSet = true;
			precision = Math.max(pr, 0);
		}

		/**
		 * Format an int argument using this conversion specification.
		 * 
		 * @param s
		 *            the int to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is f, e, E, g, or G.
		 */
		String internalsprintf(int s) throws IllegalArgumentException
		{
			String s2 = "";
			switch (conversionCharacter)
			{
			case 'd':
			case 'i':
				if (optionalh)
					s2 = printDFormat((short) s);
				else if (optionall)
					s2 = printDFormat((long) s);
				else
					s2 = printDFormat(s);
				break;
			case 'x':
			case 'X':
				if (optionalh)
					s2 = printXFormat((short) s);
				else if (optionall)
					s2 = printXFormat((long) s);
				else
					s2 = printXFormat(s);
				break;
			case 'o':
				if (optionalh)
					s2 = printOFormat((short) s);
				else if (optionall)
					s2 = printOFormat((long) s);
				else
					s2 = printOFormat(s);
				break;
			case 'c':
			case 'C':
				s2 = printCFormat((char) s);
				break;
			default:
				throw new IllegalArgumentException(
						"Cannot format a int with a format using a "
								+ conversionCharacter
								+ " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a long argument using this conversion specification.
		 * 
		 * @param s
		 *            the long to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is f, e, E, g, or G.
		 */
		String internalsprintf(long s) throws IllegalArgumentException
		{
			String s2 = "";
			switch (conversionCharacter)
			{
			case 'd':
			case 'i':
				if (optionalh)
					s2 = printDFormat((short) s);
				else if (optionall)
					s2 = printDFormat(s);
				else
					s2 = printDFormat((int) s);
				break;
			case 'x':
			case 'X':
				if (optionalh)
					s2 = printXFormat((short) s);
				else if (optionall)
					s2 = printXFormat(s);
				else
					s2 = printXFormat((int) s);
				break;
			case 'o':
				if (optionalh)
					s2 = printOFormat((short) s);
				else if (optionall)
					s2 = printOFormat(s);
				else
					s2 = printOFormat((int) s);
				break;
			case 'c':
			case 'C':
				s2 = printCFormat((char) s);
				break;
			default:
				throw new IllegalArgumentException(
						"Cannot format a long with a format using a "
								+ conversionCharacter
								+ " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a double argument using this conversion specification.
		 * 
		 * @param s
		 *            the double to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is c, C, s, S, i, d, x, X,
		 *                or o.
		 */
		String internalsprintf(double s) throws IllegalArgumentException
		{
			String s2 = "";
			switch (conversionCharacter)
			{
			case 'f':
				s2 = printFFormat(s);
				break;
			case 'E':
			case 'e':
				s2 = printEFormat(s);
				break;
			case 'G':
			case 'g':
				s2 = printGFormat(s);
				break;
			default:
				throw new IllegalArgumentException("Cannot "
						+ "format a double with a format using a "
						+ conversionCharacter + " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a String argument using this conversion specification.
		 * 
		 * @param s
		 *            the String to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is neither s nor S.
		 */
		String internalsprintf(String s) throws IllegalArgumentException
		{
			String s2 = "";
			if (conversionCharacter == 's' || conversionCharacter == 'S')
				s2 = printSFormat(s);
			else
				throw new IllegalArgumentException("Cannot "
						+ "format a String with a format using a "
						+ conversionCharacter + " conversion character.");
			return s2;
		}

		/**
		 * Format an Object argument using this conversion specification.
		 * 
		 * @param s
		 *            the Object to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is neither s nor S.
		 */
		String internalsprintf(Object s)
		{
			String s2 = "";
			if (conversionCharacter == 's' || conversionCharacter == 'S')
				s2 = printSFormat(s.toString());
			else
				throw new IllegalArgumentException(
						"Cannot format a String with a format using" + " a "
								+ conversionCharacter
								+ " conversion character.");
			return s2;
		}

		/**
		 * For f format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. '+' character means that the conversion will always begin
		 * with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a
		 * ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros
		 * instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the number of digits to appear after the
		 * radix character. Padding is with trailing 0s.
		 */
		private char[] fFormatDigits(double x)
		{
			// int defaultDigits=6;
			String sx, sxOut;
			int i, j, k;
			int n1In, n2In;
			int expon = 0;
			boolean minusSign = false;
			if (x > 0.0)
				sx = Double.toString(x);
			else if (x < 0.0)
			{
				sx = Double.toString(-x);
				minusSign = true;
			}
			else
			{
				sx = Double.toString(x);
				if (sx.charAt(0) == '-')
				{
					minusSign = true;
					sx = sx.substring(1);
				}
			}
			int ePos = sx.indexOf('E');
			int rPos = sx.indexOf('.');
			if (rPos != -1)
				n1In = rPos;
			else if (ePos != -1)
				n1In = ePos;
			else
				n1In = sx.length();
			if (rPos != -1)
			{
				if (ePos != -1)
					n2In = ePos - rPos - 1;
				else
					n2In = sx.length() - rPos - 1;
			}
			else
				n2In = 0;
			if (ePos != -1)
			{
				int ie = ePos + 1;
				expon = 0;
				if (sx.charAt(ie) == '-')
				{
					for (++ie; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0')
							break;
					if (ie < sx.length())
						expon = -Integer.parseInt(sx.substring(ie));
				}
				else
				{
					if (sx.charAt(ie) == '+')
						++ie;
					for (; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0')
							break;
					if (ie < sx.length())
						expon = Integer.parseInt(sx.substring(ie));
				}
			}
			int p;
			if (precisionSet)
				p = precision;
			else
				p = defaultDigits - 1;
			char[] ca1 = sx.toCharArray();
			char[] ca2 = new char[n1In + n2In];
			char[] ca3, ca4, ca5;
			for (j = 0; j < n1In; j++)
				ca2[j] = ca1[j];
			i = j + 1;
			for (k = 0; k < n2In; j++, i++, k++)
				ca2[j] = ca1[i];
			if (n1In + expon <= 0)
			{
				ca3 = new char[-expon + n2In];
				for (j = 0, k = 0; k < (-n1In - expon); k++, j++)
					ca3[j] = '0';
				for (i = 0; i < (n1In + n2In); i++, j++)
					ca3[j] = ca2[i];
			}
			else
				ca3 = ca2;
			boolean carry = false;
			if (p < -expon + n2In)
			{
				if (expon < 0)
					i = p;
				else
					i = p + n1In;
				carry = checkForCarry(ca3, i);
				if (carry)
					carry = startSymbolicCarry(ca3, i - 1, 0);
			}
			if (n1In + expon <= 0)
			{
				ca4 = new char[2 + p];
				if (!carry)
					ca4[0] = '0';
				else
					ca4[0] = '1';
				if (alternateForm || !precisionSet || precision != 0)
				{
					ca4[1] = '.';
					for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
						ca4[j] = ca3[i];
					for (; j < ca4.length; j++)
						ca4[j] = '0';
				}
			}
			else
			{
				if (!carry)
				{
					if (alternateForm || !precisionSet || precision != 0)
						ca4 = new char[n1In + expon + p + 1];
					else
						ca4 = new char[n1In + expon];
					j = 0;
				}
				else
				{
					if (alternateForm || !precisionSet || precision != 0)
						ca4 = new char[n1In + expon + p + 2];
					else
						ca4 = new char[n1In + expon + 1];
					ca4[0] = '1';
					j = 1;
				}
				for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
					ca4[j] = ca3[i];
				for (; i < n1In + expon; i++, j++)
					ca4[j] = '0';
				if (alternateForm || !precisionSet || precision != 0)
				{
					ca4[j] = '.';
					j++;
					for (k = 0; i < ca3.length && k < p; i++, j++, k++)
						ca4[j] = ca3[i];
					for (; j < ca4.length; j++)
						ca4[j] = '0';
				}
			}
			int nZeros = 0;
			if (!leftJustify && leadingZeros)
			{
				int xThousands = 0;
				if (thousands)
				{
					int xlead = 0;
					if (ca4[0] == '+' || ca4[0] == '-' || ca4[0] == ' ')
						xlead = 1;
					int xdp = xlead;
					for (; xdp < ca4.length; xdp++)
						if (ca4[xdp] == '.')
							break;
					xThousands = (xdp - xlead) / 3;
				}
				if (fieldWidthSet)
					nZeros = fieldWidth - ca4.length;
				if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
					nZeros--;
				nZeros -= xThousands;
				if (nZeros < 0)
					nZeros = 0;
			}
			j = 0;
			if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
			{
				ca5 = new char[ca4.length + nZeros + 1];
				j++;
			}
			else
				ca5 = new char[ca4.length + nZeros];
			if (!minusSign)
			{
				if (leadingSign)
					ca5[0] = '+';
				if (leadingSpace)
					ca5[0] = ' ';
			}
			else
				ca5[0] = '-';
			for (i = 0; i < nZeros; i++, j++)
				ca5[j] = '0';
			for (i = 0; i < ca4.length; i++, j++)
				ca5[j] = ca4[i];

			int lead = 0;
			if (ca5[0] == '+' || ca5[0] == '-' || ca5[0] == ' ')
				lead = 1;
			int dp = lead;
			for (; dp < ca5.length; dp++)
				if (ca5[dp] == '.')
					break;
			int nThousands = (dp - lead) / 3;
			// Localize the decimal point.
			if (dp < ca5.length)
				ca5[dp] = dfs.getDecimalSeparator();
			char[] ca6 = ca5;
			if (thousands && nThousands > 0)
			{
				ca6 = new char[ca5.length + nThousands + lead];
				ca6[0] = ca5[0];
				for (i = lead, k = lead; i < dp; i++)
				{
					if (i > 0 && (dp - i) % 3 == 0)
					{
						// ca6[k]=',';
						ca6[k] = dfs.getGroupingSeparator();
						ca6[k + 1] = ca5[i];
						k += 2;
					}
					else
					{
						ca6[k] = ca5[i];
						k++;
					}
				}
				for (; i < ca5.length; i++, k++)
				{
					ca6[k] = ca5[i];
				}
			}
			return ca6;
		}

		/**
		 * An intermediate routine on the way to creating an f format String.
		 * The method decides whether the input double value is an infinity,
		 * not-a-number, or a finite double and formats each type of input
		 * appropriately.
		 * 
		 * @param x
		 *            the double value to be formatted.
		 * @return the converted double value.
		 */
		private String fFormatString(double x)
		{
			boolean noDigits = false;
			char[] ca6, ca7;
			if (Double.isInfinite(x))
			{
				if (x == Double.POSITIVE_INFINITY)
				{
					if (leadingSign)
						ca6 = "+Inf".toCharArray();
					else if (leadingSpace)
						ca6 = " Inf".toCharArray();
					else
						ca6 = "Inf".toCharArray();
				}
				else
					ca6 = "-Inf".toCharArray();
				noDigits = true;
			}
			else if (Double.isNaN(x))
			{
				if (leadingSign)
					ca6 = "+NaN".toCharArray();
				else if (leadingSpace)
					ca6 = " NaN".toCharArray();
				else
					ca6 = "NaN".toCharArray();
				noDigits = true;
			}
			else
				ca6 = fFormatDigits(x);
			ca7 = applyFloatPadding(ca6, false);
			return new String(ca7);
		}

		/**
		 * For e format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. '+' character means that the conversion will always begin
		 * with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a
		 * ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros
		 * instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear
		 * after the radix character. Padding is with trailing 0s.
		 * 
		 * The behavior is like printf. One (hopefully the only) exception is
		 * that the minimum number of exponent digits is 3 instead of 2 for e
		 * and E formats when the optional L is used before the e, E, g, or G
		 * conversion character. The optional L does not imply conversion to a
		 * long long double.
		 */
		private char[] eFormatDigits(double x, char eChar)
		{
			char[] ca1, ca2, ca3;
			// int defaultDigits=6;
			String sx, sxOut;
			int i, j, k, p;
			int n1In, n2In;
			int expon = 0;
			int ePos, rPos, eSize;
			boolean minusSign = false;
			if (x > 0.0)
				sx = Double.toString(x);
			else if (x < 0.0)
			{
				sx = Double.toString(-x);
				minusSign = true;
			}
			else
			{
				sx = Double.toString(x);
				if (sx.charAt(0) == '-')
				{
					minusSign = true;
					sx = sx.substring(1);
				}
			}
			ePos = sx.indexOf('E');
			if (ePos == -1)
				ePos = sx.indexOf('e');
			rPos = sx.indexOf('.');
			if (rPos != -1)
				n1In = rPos;
			else if (ePos != -1)
				n1In = ePos;
			else
				n1In = sx.length();
			if (rPos != -1)
			{
				if (ePos != -1)
					n2In = ePos - rPos - 1;
				else
					n2In = sx.length() - rPos - 1;
			}
			else
				n2In = 0;
			if (ePos != -1)
			{
				int ie = ePos + 1;
				expon = 0;
				if (sx.charAt(ie) == '-')
				{
					for (++ie; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0')
							break;
					if (ie < sx.length())
						expon = -Integer.parseInt(sx.substring(ie));
				}
				else
				{
					if (sx.charAt(ie) == '+')
						++ie;
					for (; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0')
							break;
					if (ie < sx.length())
						expon = Integer.parseInt(sx.substring(ie));
				}
			}
			if (rPos != -1)
				expon += rPos - 1;
			if (precisionSet)
				p = precision;
			else
				p = defaultDigits - 1;
			if (rPos != -1 && ePos != -1)
				ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos))
						.toCharArray();
			else if (rPos != -1)
				ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1))
						.toCharArray();
			else if (ePos != -1)
				ca1 = sx.substring(0, ePos).toCharArray();
			else
				ca1 = sx.toCharArray();
			boolean carry = false;
			int i0 = 0;
			if (ca1[0] != '0')
				i0 = 0;
			else
				for (i0 = 0; i0 < ca1.length; i0++)
					if (ca1[i0] != '0')
						break;
			if (i0 + p < ca1.length - 1)
			{
				carry = checkForCarry(ca1, i0 + p + 1);
				if (carry)
					carry = startSymbolicCarry(ca1, i0 + p, i0);
				if (carry)
				{
					ca2 = new char[i0 + p + 1];
					ca2[i0] = '1';
					for (j = 0; j < i0; j++)
						ca2[j] = '0';
					for (i = i0, j = i0 + 1; j < p + 1; i++, j++)
						ca2[j] = ca1[i];
					expon++;
					ca1 = ca2;
				}
			}
			if (Math.abs(expon) < 100 && !optionalL)
				eSize = 4;
			else
				eSize = 5;
			if (alternateForm || !precisionSet || precision != 0)
				ca2 = new char[2 + p + eSize];
			else
				ca2 = new char[1 + eSize];
			if (ca1[0] != '0')
			{
				ca2[0] = ca1[0];
				j = 1;
			}
			else
			{
				for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++)
					if (ca1[j] != '0')
						break;
				if ((ePos != -1 && j < ePos) || (ePos == -1 && j < ca1.length))
				{
					ca2[0] = ca1[j];
					expon -= j;
					j++;
				}
				else
				{
					ca2[0] = '0';
					j = 2;
				}
			}
			if (alternateForm || !precisionSet || precision != 0)
			{
				ca2[1] = '.';
				i = 2;
			}
			else
				i = 1;
			for (k = 0; k < p && j < ca1.length; j++, i++, k++)
				ca2[i] = ca1[j];
			for (; i < ca2.length - eSize; i++)
				ca2[i] = '0';
			ca2[i++] = eChar;
			if (expon < 0)
				ca2[i++] = '-';
			else
				ca2[i++] = '+';
			expon = Math.abs(expon);
			if (expon >= 100)
			{
				switch (expon / 100)
				{
				case 1:
					ca2[i] = '1';
					break;
				case 2:
					ca2[i] = '2';
					break;
				case 3:
					ca2[i] = '3';
					break;
				case 4:
					ca2[i] = '4';
					break;
				case 5:
					ca2[i] = '5';
					break;
				case 6:
					ca2[i] = '6';
					break;
				case 7:
					ca2[i] = '7';
					break;
				case 8:
					ca2[i] = '8';
					break;
				case 9:
					ca2[i] = '9';
					break;
				}
				i++;
			}
			switch ((expon % 100) / 10)
			{
			case 0:
				ca2[i] = '0';
				break;
			case 1:
				ca2[i] = '1';
				break;
			case 2:
				ca2[i] = '2';
				break;
			case 3:
				ca2[i] = '3';
				break;
			case 4:
				ca2[i] = '4';
				break;
			case 5:
				ca2[i] = '5';
				break;
			case 6:
				ca2[i] = '6';
				break;
			case 7:
				ca2[i] = '7';
				break;
			case 8:
				ca2[i] = '8';
				break;
			case 9:
				ca2[i] = '9';
				break;
			}
			i++;
			switch (expon % 10)
			{
			case 0:
				ca2[i] = '0';
				break;
			case 1:
				ca2[i] = '1';
				break;
			case 2:
				ca2[i] = '2';
				break;
			case 3:
				ca2[i] = '3';
				break;
			case 4:
				ca2[i] = '4';
				break;
			case 5:
				ca2[i] = '5';
				break;
			case 6:
				ca2[i] = '6';
				break;
			case 7:
				ca2[i] = '7';
				break;
			case 8:
				ca2[i] = '8';
				break;
			case 9:
				ca2[i] = '9';
				break;
			}
			int nZeros = 0;
			if (!leftJustify && leadingZeros)
			{
				int xThousands = 0;
				if (thousands)
				{
					int xlead = 0;
					if (ca2[0] == '+' || ca2[0] == '-' || ca2[0] == ' ')
						xlead = 1;
					int xdp = xlead;
					for (; xdp < ca2.length; xdp++)
						if (ca2[xdp] == '.')
							break;
					xThousands = (xdp - xlead) / 3;
				}
				if (fieldWidthSet)
					nZeros = fieldWidth - ca2.length;
				if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
					nZeros--;
				nZeros -= xThousands;
				if (nZeros < 0)
					nZeros = 0;
			}
			j = 0;
			if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
			{
				ca3 = new char[ca2.length + nZeros + 1];
				j++;
			}
			else
				ca3 = new char[ca2.length + nZeros];
			if (!minusSign)
			{
				if (leadingSign)
					ca3[0] = '+';
				if (leadingSpace)
					ca3[0] = ' ';
			}
			else
				ca3[0] = '-';
			for (k = 0; k < nZeros; j++, k++)
				ca3[j] = '0';
			for (i = 0; i < ca2.length && j < ca3.length; i++, j++)
				ca3[j] = ca2[i];

			int lead = 0;
			if (ca3[0] == '+' || ca3[0] == '-' || ca3[0] == ' ')
				lead = 1;
			int dp = lead;
			for (; dp < ca3.length; dp++)
				if (ca3[dp] == '.')
					break;
			int nThousands = dp / 3;
			// Localize the decimal point.
			if (dp < ca3.length)
				ca3[dp] = dfs.getDecimalSeparator();
			char[] ca4 = ca3;
			if (thousands && nThousands > 0)
			{
				ca4 = new char[ca3.length + nThousands + lead];
				ca4[0] = ca3[0];
				for (i = lead, k = lead; i < dp; i++)
				{
					if (i > 0 && (dp - i) % 3 == 0)
					{
						// ca4[k]=',';
						ca4[k] = dfs.getGroupingSeparator();
						ca4[k + 1] = ca3[i];
						k += 2;
					}
					else
					{
						ca4[k] = ca3[i];
						k++;
					}
				}
				for (; i < ca3.length; i++, k++)
					ca4[k] = ca3[i];
			}
			return ca4;
		}

		/**
		 * Check to see if the digits that are going to be truncated because of
		 * the precision should force a round in the preceding digits.
		 * 
		 * @param ca1
		 *            the array of digits
		 * @param icarry
		 *            the index of the first digit that is to be truncated from
		 *            the print
		 * @return <code>true</code> if the truncation forces a round that will
		 *         change the print
		 */
		private boolean checkForCarry(char[] ca1, int icarry)
		{
			boolean carry = false;
			if (icarry < ca1.length)
			{
				if (ca1[icarry] == '6' || ca1[icarry] == '7'
						|| ca1[icarry] == '8' || ca1[icarry] == '9')
					carry = true;
				else if (ca1[icarry] == '5')
				{
					int ii = icarry + 1;
					for (; ii < ca1.length; ii++)
						if (ca1[ii] != '0')
							break;
					carry = ii < ca1.length;
					if (!carry && icarry > 0)
					{
						carry = (ca1[icarry - 1] == '1'
								|| ca1[icarry - 1] == '3'
								|| ca1[icarry - 1] == '5'
								|| ca1[icarry - 1] == '7' || ca1[icarry - 1] == '9');
					}
				}
			}
			return carry;
		}

		/**
		 * Start the symbolic carry process. The process is not quite finished
		 * because the symbolic carry may change the length of the string and
		 * change the exponent (in e format).
		 * 
		 * @param cLast
		 *            index of the last digit changed by the round
		 * @param cFirst
		 *            index of the first digit allowed to be changed by this
		 *            phase of the round
		 * @return <code>true</code> if the carry forces a round that will
		 *         change the print still more
		 */
		private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst)
		{
			boolean carry = true;
			for (int i = cLast; carry && i >= cFirst; i--)
			{
				carry = false;
				switch (ca[i])
				{
				case '0':
					ca[i] = '1';
					break;
				case '1':
					ca[i] = '2';
					break;
				case '2':
					ca[i] = '3';
					break;
				case '3':
					ca[i] = '4';
					break;
				case '4':
					ca[i] = '5';
					break;
				case '5':
					ca[i] = '6';
					break;
				case '6':
					ca[i] = '7';
					break;
				case '7':
					ca[i] = '8';
					break;
				case '8':
					ca[i] = '9';
					break;
				case '9':
					ca[i] = '0';
					carry = true;
					break;
				}
			}
			return carry;
		}

		/**
		 * An intermediate routine on the way to creating an e format String.
		 * The method decides whether the input double value is an infinity,
		 * not-a-number, or a finite double and formats each type of input
		 * appropriately.
		 * 
		 * @param x
		 *            the double value to be formatted.
		 * @param eChar
		 *            an 'e' or 'E' to use in the converted double value.
		 * @return the converted double value.
		 */
		private String eFormatString(double x, char eChar)
		{
			boolean noDigits = false;
			char[] ca4, ca5;
			if (Double.isInfinite(x))
			{
				if (x == Double.POSITIVE_INFINITY)
				{
					if (leadingSign)
						ca4 = "+Inf".toCharArray();
					else if (leadingSpace)
						ca4 = " Inf".toCharArray();
					else
						ca4 = "Inf".toCharArray();
				}
				else
					ca4 = "-Inf".toCharArray();
				noDigits = true;
			}
			else if (Double.isNaN(x))
			{
				if (leadingSign)
					ca4 = "+NaN".toCharArray();
				else if (leadingSpace)
					ca4 = " NaN".toCharArray();
				else
					ca4 = "NaN".toCharArray();
				noDigits = true;
			}
			else
				ca4 = eFormatDigits(x, eChar);
			ca5 = applyFloatPadding(ca4, false);
			return new String(ca5);
		}

		/**
		 * Apply zero or blank, left or right padding.
		 * 
		 * @param ca4
		 *            array of characters before padding is finished
		 * @param noDigits
		 *            NaN or signed Inf
		 * @return a padded array of characters
		 */
		private char[] applyFloatPadding(char[] ca4, boolean noDigits)
		{
			char[] ca5 = ca4;
			if (fieldWidthSet)
			{
				int i, j, nBlanks;
				if (leftJustify)
				{
					nBlanks = fieldWidth - ca4.length;
					if (nBlanks > 0)
					{
						ca5 = new char[ca4.length + nBlanks];
						for (i = 0; i < ca4.length; i++)
							ca5[i] = ca4[i];
						for (j = 0; j < nBlanks; j++, i++)
							ca5[i] = ' ';
					}
				}
				else if (!leadingZeros || noDigits)
				{
					nBlanks = fieldWidth - ca4.length;
					if (nBlanks > 0)
					{
						ca5 = new char[ca4.length + nBlanks];
						for (i = 0; i < nBlanks; i++)
							ca5[i] = ' ';
						for (j = 0; j < ca4.length; i++, j++)
							ca5[i] = ca4[j];
					}
				}
				else if (leadingZeros)
				{
					nBlanks = fieldWidth - ca4.length;
					if (nBlanks > 0)
					{
						ca5 = new char[ca4.length + nBlanks];
						i = 0;
						j = 0;
						if (ca4[0] == '-')
						{
							ca5[0] = '-';
							i++;
							j++;
						}
						for (int k = 0; k < nBlanks; i++, k++)
							ca5[i] = '0';
						for (; j < ca4.length; i++, j++)
							ca5[i] = ca4[j];
					}
				}
			}
			return ca5;
		}

		/**
		 * Format method for the f conversion character.
		 * 
		 * @param x
		 *            the double to format.
		 * @return the formatted String.
		 */
		private String printFFormat(double x)
		{
			return fFormatString(x);
		}

		/**
		 * Format method for the e or E conversion character.
		 * 
		 * @param x
		 *            the double to format.
		 * @return the formatted String.
		 */
		private String printEFormat(double x)
		{
			if (conversionCharacter == 'e')
				return eFormatString(x, 'e');
			else
				return eFormatString(x, 'E');
		}

		/**
		 * Format method for the g conversion character.
		 * 
		 * For g format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. '+' character means that the conversion will always begin
		 * with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a
		 * ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros
		 * instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear
		 * after the radix character. Padding is with trailing 0s.
		 * 
		 * @param x
		 *            the double to format.
		 * @return the formatted String.
		 */
		private String printGFormat(double x)
		{
			String sx, sy, sz, ret;
			int savePrecision = precision;
			int i;
			char[] ca4, ca5;
			boolean noDigits = false;
			if (Double.isInfinite(x))
			{
				if (x == Double.POSITIVE_INFINITY)
				{
					if (leadingSign)
						ca4 = "+Inf".toCharArray();
					else if (leadingSpace)
						ca4 = " Inf".toCharArray();
					else
						ca4 = "Inf".toCharArray();
				}
				else
					ca4 = "-Inf".toCharArray();
				noDigits = true;
			}
			else if (Double.isNaN(x))
			{
				if (leadingSign)
					ca4 = "+NaN".toCharArray();
				else if (leadingSpace)
					ca4 = " NaN".toCharArray();
				else
					ca4 = "NaN".toCharArray();
				noDigits = true;
			}
			else
			{
				if (!precisionSet)
					precision = defaultDigits;
				if (precision == 0)
					precision = 1;
				int ePos = -1;
				if (conversionCharacter == 'g')
				{
					sx = eFormatString(x, 'e').trim();
					ePos = sx.indexOf('e');
				}
				else
				{
					sx = eFormatString(x, 'E').trim();
					ePos = sx.indexOf('E');
				}
				i = ePos + 1;
				int expon = 0;
				if (sx.charAt(i) == '-')
				{
					for (++i; i < sx.length(); i++)
						if (sx.charAt(i) != '0')
							break;
					if (i < sx.length())
						expon = -Integer.parseInt(sx.substring(i));
				}
				else
				{
					if (sx.charAt(i) == '+')
						++i;
					for (; i < sx.length(); i++)
						if (sx.charAt(i) != '0')
							break;
					if (i < sx.length())
						expon = Integer.parseInt(sx.substring(i));
				}
				// Trim trailing zeros.
				// If the radix character is not followed by
				// a digit, trim it, too.
				if (!alternateForm)
				{
					if (expon >= -4 && expon < precision)
						sy = fFormatString(x).trim();
					else
						sy = sx.substring(0, ePos);
					i = sy.length() - 1;
					for (; i >= 0; i--)
						if (sy.charAt(i) != '0')
							break;
					if (i >= 0 && sy.charAt(i) == '.')
						i--;
					if (i == -1)
						sz = "0";
					else if (!Character.isDigit(sy.charAt(i)))
						sz = sy.substring(0, i + 1) + "0";
					else
						sz = sy.substring(0, i + 1);
					if (expon >= -4 && expon < precision)
						ret = sz;
					else
						ret = sz + sx.substring(ePos);
				}
				else
				{
					if (expon >= -4 && expon < precision)
						ret = fFormatString(x).trim();
					else
						ret = sx;
				}
				// leading space was trimmed off during
				// construction
				if (leadingSpace)
					if (x >= 0)
						ret = " " + ret;
				ca4 = ret.toCharArray();
			}
			// Pad with blanks or zeros.
			ca5 = applyFloatPadding(ca4, false);
			precision = savePrecision;
			return new String(ca5);
		}

		/**
		 * Format method for the d conversion specifer and short argument.
		 * 
		 * For d format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. A '+' character means that the conversion will always begin
		 * with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a
		 * ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros
		 * instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the short to format.
		 * @return the formatted String.
		 */
		private String printDFormat(short x)
		{
			return printDFormat(Short.toString(x));
		}

		/**
		 * Format method for the d conversion character and long argument.
		 * 
		 * For d format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. A '+' character means that the conversion will always begin
		 * with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a
		 * ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros
		 * instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the long to format.
		 * @return the formatted String.
		 */
		private String printDFormat(long x)
		{
			return printDFormat(Long.toString(x));
		}

		/**
		 * Format method for the d conversion character and int argument.
		 * 
		 * For d format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. A '+' character means that the conversion will always begin
		 * with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a
		 * ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros
		 * instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the int to format.
		 * @return the formatted String.
		 */
		private String printDFormat(int x)
		{
			return printDFormat(Integer.toString(x));
		}

		/**
		 * Utility method for formatting using the d conversion character.
		 * 
		 * @param sx
		 *            the String to format, the result of converting a short,
		 *            int, or long to a String.
		 * @return the formatted String.
		 */
		private String printDFormat(String sx)
		{
			int nLeadingZeros = 0;
			int nBlanks = 0, n = 0;
			int i = 0, jFirst = 0;
			boolean neg = sx.charAt(0) == '-';
			if (sx.equals("0") && precisionSet && precision == 0)
				sx = "";
			if (!neg)
			{
				if (precisionSet && sx.length() < precision)
					nLeadingZeros = precision - sx.length();
			}
			else
			{
				if (precisionSet && (sx.length() - 1) < precision)
					nLeadingZeros = precision - sx.length() + 1;
			}
			if (nLeadingZeros < 0)
				nLeadingZeros = 0;
			if (fieldWidthSet)
			{
				nBlanks = fieldWidth - nLeadingZeros - sx.length();
				if (!neg && (leadingSign || leadingSpace))
					nBlanks--;
			}
			if (nBlanks < 0)
				nBlanks = 0;
			if (leadingSign)
				n++;
			else if (leadingSpace)
				n++;
			n += nBlanks;
			n += nLeadingZeros;
			n += sx.length();
			char[] ca = new char[n];
			if (leftJustify)
			{
				if (neg)
					ca[i++] = '-';
				else if (leadingSign)
					ca[i++] = '+';
				else if (leadingSpace)
					ca[i++] = ' ';
				char[] csx = sx.toCharArray();
				jFirst = neg ? 1 : 0;
				for (int j = 0; j < nLeadingZeros; i++, j++)
					ca[i] = '0';
				for (int j = jFirst; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for (int j = 0; j < nBlanks; i++, j++)
					ca[i] = ' ';
			}
			else
			{
				if (!leadingZeros)
				{
					for (i = 0; i < nBlanks; i++)
						ca[i] = ' ';
					if (neg)
						ca[i++] = '-';
					else if (leadingSign)
						ca[i++] = '+';
					else if (leadingSpace)
						ca[i++] = ' ';
				}
				else
				{
					if (neg)
						ca[i++] = '-';
					else if (leadingSign)
						ca[i++] = '+';
					else if (leadingSpace)
						ca[i++] = ' ';
					for (int j = 0; j < nBlanks; j++, i++)
						ca[i] = '0';
				}
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				jFirst = neg ? 1 : 0;
				for (int j = jFirst; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			return new String(ca);
		}

		/**
		 * Format method for the x conversion character and short argument.
		 * 
		 * For x format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the short to format.
		 * @return the formatted String.
		 */
		private String printXFormat(short x)
		{
			String sx = null;
			if (x == Short.MIN_VALUE)
				sx = "8000";
			else if (x < 0)
			{
				String t;
				if (x == Short.MIN_VALUE)
					t = "0";
				else
				{
					t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16);
					if (t.charAt(0) == 'F' || t.charAt(0) == 'f')
						t = t.substring(16, 32);
				}
				switch (t.length())
				{
				case 1:
					sx = "800" + t;
					break;
				case 2:
					sx = "80" + t;
					break;
				case 3:
					sx = "8" + t;
					break;
				case 4:
					switch (t.charAt(0))
					{
					case '1':
						sx = "9" + t.substring(1, 4);
						break;
					case '2':
						sx = "a" + t.substring(1, 4);
						break;
					case '3':
						sx = "b" + t.substring(1, 4);
						break;
					case '4':
						sx = "c" + t.substring(1, 4);
						break;
					case '5':
						sx = "d" + t.substring(1, 4);
						break;
					case '6':
						sx = "e" + t.substring(1, 4);
						break;
					case '7':
						sx = "f" + t.substring(1, 4);
						break;
					}
					break;
				}
			}
			else
				sx = Integer.toString((int) x, 16);
			return printXFormat(sx);
		}

		/**
		 * Format method for the x conversion character and long argument.
		 * 
		 * For x format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the long to format.
		 * @return the formatted String.
		 */
		private String printXFormat(long x)
		{
			String sx = null;
			if (x == Long.MIN_VALUE)
				sx = "8000000000000000";
			else if (x < 0)
			{
				String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16);
				switch (t.length())
				{
				case 1:
					sx = "800000000000000" + t;
					break;
				case 2:
					sx = "80000000000000" + t;
					break;
				case 3:
					sx = "8000000000000" + t;
					break;
				case 4:
					sx = "800000000000" + t;
					break;
				case 5:
					sx = "80000000000" + t;
					break;
				case 6:
					sx = "8000000000" + t;
					break;
				case 7:
					sx = "800000000" + t;
					break;
				case 8:
					sx = "80000000" + t;
					break;
				case 9:
					sx = "8000000" + t;
					break;
				case 10:
					sx = "800000" + t;
					break;
				case 11:
					sx = "80000" + t;
					break;
				case 12:
					sx = "8000" + t;
					break;
				case 13:
					sx = "800" + t;
					break;
				case 14:
					sx = "80" + t;
					break;
				case 15:
					sx = "8" + t;
					break;
				case 16:
					switch (t.charAt(0))
					{
					case '1':
						sx = "9" + t.substring(1, 16);
						break;
					case '2':
						sx = "a" + t.substring(1, 16);
						break;
					case '3':
						sx = "b" + t.substring(1, 16);
						break;
					case '4':
						sx = "c" + t.substring(1, 16);
						break;
					case '5':
						sx = "d" + t.substring(1, 16);
						break;
					case '6':
						sx = "e" + t.substring(1, 16);
						break;
					case '7':
						sx = "f" + t.substring(1, 16);
						break;
					}
					break;
				}
			}
			else
				sx = Long.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Format method for the x conversion character and int argument.
		 * 
		 * For x format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the int to format.
		 * @return the formatted String.
		 */
		private String printXFormat(int x)
		{
			String sx = null;
			if (x == Integer.MIN_VALUE)
				sx = "80000000";
			else if (x < 0)
			{
				String t = Integer
						.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16);
				switch (t.length())
				{
				case 1:
					sx = "8000000" + t;
					break;
				case 2:
					sx = "800000" + t;
					break;
				case 3:
					sx = "80000" + t;
					break;
				case 4:
					sx = "8000" + t;
					break;
				case 5:
					sx = "800" + t;
					break;
				case 6:
					sx = "80" + t;
					break;
				case 7:
					sx = "8" + t;
					break;
				case 8:
					switch (t.charAt(0))
					{
					case '1':
						sx = "9" + t.substring(1, 8);
						break;
					case '2':
						sx = "a" + t.substring(1, 8);
						break;
					case '3':
						sx = "b" + t.substring(1, 8);
						break;
					case '4':
						sx = "c" + t.substring(1, 8);
						break;
					case '5':
						sx = "d" + t.substring(1, 8);
						break;
					case '6':
						sx = "e" + t.substring(1, 8);
						break;
					case '7':
						sx = "f" + t.substring(1, 8);
						break;
					}
					break;
				}
			}
			else
				sx = Integer.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Utility method for formatting using the x conversion character.
		 * 
		 * @param sx
		 *            the String to format, the result of converting a short,
		 *            int, or long to a String.
		 * @return the formatted String.
		 */
		private String printXFormat(String sx)
		{
			int nLeadingZeros = 0;
			int nBlanks = 0;
			if (sx.equals("0") && precisionSet && precision == 0)
				sx = "";
			if (precisionSet)
				nLeadingZeros = precision - sx.length();
			if (nLeadingZeros < 0)
				nLeadingZeros = 0;
			if (fieldWidthSet)
			{
				nBlanks = fieldWidth - nLeadingZeros - sx.length();
				if (alternateForm)
					nBlanks = nBlanks - 2;
			}
			if (nBlanks < 0)
				nBlanks = 0;
			int n = 0;
			if (alternateForm)
				n += 2;
			n += nLeadingZeros;
			n += sx.length();
			n += nBlanks;
			char[] ca = new char[n];
			int i = 0;
			if (leftJustify)
			{
				if (alternateForm)
				{
					ca[i++] = '0';
					ca[i++] = 'x';
				}
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for (int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
			}
			else
			{
				if (!leadingZeros)
					for (int j = 0; j < nBlanks; j++, i++)
						ca[i] = ' ';
				if (alternateForm)
				{
					ca[i++] = '0';
					ca[i++] = 'x';
				}
				if (leadingZeros)
					for (int j = 0; j < nBlanks; j++, i++)
						ca[i] = '0';
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			String caReturn = new String(ca);
			if (conversionCharacter == 'X')
				caReturn = caReturn.toUpperCase();
			return caReturn;
		}

		/**
		 * Format method for the o conversion character and short argument.
		 * 
		 * For o format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means that the output begins with a
		 * leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the short to format.
		 * @return the formatted String.
		 */
		private String printOFormat(short x)
		{
			String sx = null;
			if (x == Short.MIN_VALUE)
				sx = "100000";
			else if (x < 0)
			{
				String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8);
				switch (t.length())
				{
				case 1:
					sx = "10000" + t;
					break;
				case 2:
					sx = "1000" + t;
					break;
				case 3:
					sx = "100" + t;
					break;
				case 4:
					sx = "10" + t;
					break;
				case 5:
					sx = "1" + t;
					break;
				}
			}
			else
				sx = Integer.toString((int) x, 8);
			return printOFormat(sx);
		}

		/**
		 * Format method for the o conversion character and long argument.
		 * 
		 * For o format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means that the output begins with a
		 * leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the long to format.
		 * @return the formatted String.
		 */
		private String printOFormat(long x)
		{
			String sx = null;
			if (x == Long.MIN_VALUE)
				sx = "1000000000000000000000";
			else if (x < 0)
			{
				String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8);
				switch (t.length())
				{
				case 1:
					sx = "100000000000000000000" + t;
					break;
				case 2:
					sx = "10000000000000000000" + t;
					break;
				case 3:
					sx = "1000000000000000000" + t;
					break;
				case 4:
					sx = "100000000000000000" + t;
					break;
				case 5:
					sx = "10000000000000000" + t;
					break;
				case 6:
					sx = "1000000000000000" + t;
					break;
				case 7:
					sx = "100000000000000" + t;
					break;
				case 8:
					sx = "10000000000000" + t;
					break;
				case 9:
					sx = "1000000000000" + t;
					break;
				case 10:
					sx = "100000000000" + t;
					break;
				case 11:
					sx = "10000000000" + t;
					break;
				case 12:
					sx = "1000000000" + t;
					break;
				case 13:
					sx = "100000000" + t;
					break;
				case 14:
					sx = "10000000" + t;
					break;
				case 15:
					sx = "1000000" + t;
					break;
				case 16:
					sx = "100000" + t;
					break;
				case 17:
					sx = "10000" + t;
					break;
				case 18:
					sx = "1000" + t;
					break;
				case 19:
					sx = "100" + t;
					break;
				case 20:
					sx = "10" + t;
					break;
				case 21:
					sx = "1" + t;
					break;
				}
			}
			else
				sx = Long.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Format method for the o conversion character and int argument.
		 * 
		 * For o format, the flag character '-', means that the output should be
		 * left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means that the output begins with a
		 * leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear.
		 * Padding is with leading 0s.
		 * 
		 * @param x
		 *            the int to format.
		 * @return the formatted String.
		 */
		private String printOFormat(int x)
		{
			String sx = null;
			if (x == Integer.MIN_VALUE)
				sx = "20000000000";
			else if (x < 0)
			{
				String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8);
				switch (t.length())
				{
				case 1:
					sx = "2000000000" + t;
					break;
				case 2:
					sx = "200000000" + t;
					break;
				case 3:
					sx = "20000000" + t;
					break;
				case 4:
					sx = "2000000" + t;
					break;
				case 5:
					sx = "200000" + t;
					break;
				case 6:
					sx = "20000" + t;
					break;
				case 7:
					sx = "2000" + t;
					break;
				case 8:
					sx = "200" + t;
					break;
				case 9:
					sx = "20" + t;
					break;
				case 10:
					sx = "2" + t;
					break;
				case 11:
					sx = "3" + t.substring(1);
					break;
				}
			}
			else
				sx = Integer.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Utility method for formatting using the o conversion character.
		 * 
		 * @param sx
		 *            the String to format, the result of converting a short,
		 *            int, or long to a String.
		 * @return the formatted String.
		 */
		private String printOFormat(String sx)
		{
			int nLeadingZeros = 0;
			int nBlanks = 0;
			if (sx.equals("0") && precisionSet && precision == 0)
				sx = "";
			if (precisionSet)
				nLeadingZeros = precision - sx.length();
			if (alternateForm)
				nLeadingZeros++;
			if (nLeadingZeros < 0)
				nLeadingZeros = 0;
			if (fieldWidthSet)
				nBlanks = fieldWidth - nLeadingZeros - sx.length();
			if (nBlanks < 0)
				nBlanks = 0;
			int n = nLeadingZeros + sx.length() + nBlanks;
			char[] ca = new char[n];
			int i;
			if (leftJustify)
			{
				for (i = 0; i < nLeadingZeros; i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for (int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
			}
			else
			{
				if (leadingZeros)
					for (i = 0; i < nBlanks; i++)
						ca[i] = '0';
				else
					for (i = 0; i < nBlanks; i++)
						ca[i] = ' ';
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			return new String(ca);
		}

		/**
		 * Format method for the c conversion character and char argument.
		 * 
		 * The only flag character that affects c format is the '-', meaning
		 * that the output should be left justified within the field. The
		 * default is to pad with blanks on the left.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. Padding is with blanks by default. The default width is 1.
		 * 
		 * The precision, if set, is ignored.
		 * 
		 * @param x
		 *            the char to format.
		 * @return the formatted String.
		 */
		private String printCFormat(char x)
		{
			int nPrint = 1;
			int width = fieldWidth;
			if (!fieldWidthSet)
				width = nPrint;
			char[] ca = new char[width];
			int i = 0;
			if (leftJustify)
			{
				ca[0] = x;
				for (i = 1; i <= width - nPrint; i++)
					ca[i] = ' ';
			}
			else
			{
				for (i = 0; i < width - nPrint; i++)
					ca[i] = ' ';
				ca[i] = x;
			}
			return new String(ca);
		}

		/**
		 * Format method for the s conversion character and String argument.
		 * 
		 * The only flag character that affects s format is the '-', meaning
		 * that the output should be left justified within the field. The
		 * default is to pad with blanks on the left.
		 * 
		 * The field width is treated as the minimum number of characters to be
		 * printed. The default is the smaller of the number of characters in
		 * the the input and the precision. Padding is with blanks by default.
		 * 
		 * The precision, if set, specifies the maximum number of characters to
		 * be printed from the string. A null digit string is treated as a 0.
		 * The default is not to set a maximum number of characters to be
		 * printed.
		 * 
		 * @param x
		 *            the String to format.
		 * @return the formatted String.
		 */
		private String printSFormat(String x)
		{
			int nPrint = x.length();
			int width = fieldWidth;
			if (precisionSet && nPrint > precision)
				nPrint = precision;
			if (!fieldWidthSet)
				width = nPrint;
			int n = 0;
			if (width > nPrint)
				n += width - nPrint;
			if (nPrint >= x.length())
				n += x.length();
			else
				n += nPrint;
			char[] ca = new char[n];
			int i = 0;
			if (leftJustify)
			{
				if (nPrint >= x.length())
				{
					char[] csx = x.toCharArray();
					for (i = 0; i < x.length(); i++)
						ca[i] = csx[i];
				}
				else
				{
					char[] csx = x.substring(0, nPrint).toCharArray();
					for (i = 0; i < nPrint; i++)
						ca[i] = csx[i];
				}
				for (int j = 0; j < width - nPrint; j++, i++)
					ca[i] = ' ';
			}
			else
			{
				for (i = 0; i < width - nPrint; i++)
					ca[i] = ' ';
				if (nPrint >= x.length())
				{
					char[] csx = x.toCharArray();
					for (int j = 0; j < x.length(); i++, j++)
						ca[i] = csx[j];
				}
				else
				{
					char[] csx = x.substring(0, nPrint).toCharArray();
					for (int j = 0; j < nPrint; i++, j++)
						ca[i] = csx[j];
				}
			}
			return new String(ca);
		}

		/**
		 * Check for a conversion character. If it is there, store it.
		 * 
		 * @param x
		 *            the String to format.
		 * @return <code>true</code> if the conversion character is there, and
		 *         <code>false</code> otherwise.
		 */
		private boolean setConversionCharacter()
		{
			/* idfgGoxXeEcs */
			boolean ret = false;
			conversionCharacter = '\0';
			if (pos < fmt.length())
			{
				char c = fmt.charAt(pos);
				if (c == 'i' || c == 'd' || c == 'f' || c == 'g' || c == 'G'
						|| c == 'o' || c == 'x' || c == 'X' || c == 'e'
						|| c == 'E' || c == 'c' || c == 's' || c == '%')
				{
					conversionCharacter = c;
					pos++;
					ret = true;
				}
			}
			return ret;
		}

		/**
		 * Check for an h, l, or L in a format. An L is used to control the
		 * minimum number of digits in an exponent when using floating point
		 * formats. An l or h is used to control conversion of the input to a
		 * long or short, respectively, before formatting. If any of these is
		 * present, store them.
		 */
		private void setOptionalHL()
		{
			optionalh = false;
			optionall = false;
			optionalL = false;
			if (pos < fmt.length())
			{
				char c = fmt.charAt(pos);
				if (c == 'h')
				{
					optionalh = true;
					pos++;
				}
				else if (c == 'l')
				{
					optionall = true;
					pos++;
				}
				else if (c == 'L')
				{
					optionalL = true;
					pos++;
				}
			}
		}

		/**
		 * Set the precision.
		 */
		private void setPrecision()
		{
			int firstPos = pos;
			precisionSet = false;
			if (pos < fmt.length() && fmt.charAt(pos) == '.')
			{
				pos++;
				if ((pos < fmt.length()) && (fmt.charAt(pos) == '*'))
				{
					pos++;
					if (!setPrecisionArgPosition())
					{
						variablePrecision = true;
						precisionSet = true;
					}
					return;
				}
				else
				{
					while (pos < fmt.length())
					{
						char c = fmt.charAt(pos);
						if (Character.isDigit(c))
							pos++;
						else
							break;
					}
					if (pos > firstPos + 1)
					{
						String sz = fmt.substring(firstPos + 1, pos);
						precision = Integer.parseInt(sz);
						precisionSet = true;
					}
				}
			}
		}

		/**
		 * Set the field width.
		 */
		private void setFieldWidth()
		{
			int firstPos = pos;
			fieldWidth = 0;
			fieldWidthSet = false;
			if ((pos < fmt.length()) && (fmt.charAt(pos) == '*'))
			{
				pos++;
				if (!setFieldWidthArgPosition())
				{
					variableFieldWidth = true;
					fieldWidthSet = true;
				}
			}
			else
			{
				while (pos < fmt.length())
				{
					char c = fmt.charAt(pos);
					if (Character.isDigit(c))
						pos++;
					else
						break;
				}
				if (firstPos < pos && firstPos < fmt.length())
				{
					String sz = fmt.substring(firstPos, pos);
					fieldWidth = Integer.parseInt(sz);
					fieldWidthSet = true;
				}
			}
		}

		/**
		 * Store the digits <code>n</code> in %n$ forms.
		 */
		private void setArgPosition()
		{
			int xPos;
			for (xPos = pos; xPos < fmt.length(); xPos++)
			{
				if (!Character.isDigit(fmt.charAt(xPos)))
					break;
			}
			if (xPos > pos && xPos < fmt.length())
			{
				if (fmt.charAt(xPos) == '$')
				{
					positionalSpecification = true;
					argumentPosition = Integer.parseInt(fmt
							.substring(pos, xPos));
					pos = xPos + 1;
				}
			}
		}

		/**
		 * Store the digits <code>n</code> in *n$ forms.
		 */
		private boolean setFieldWidthArgPosition()
		{
			boolean ret = false;
			int xPos;
			for (xPos = pos; xPos < fmt.length(); xPos++)
			{
				if (!Character.isDigit(fmt.charAt(xPos)))
					break;
			}
			if (xPos > pos && xPos < fmt.length())
			{
				if (fmt.charAt(xPos) == '$')
				{
					positionalFieldWidth = true;
					argumentPositionForFieldWidth = Integer.parseInt(fmt
							.substring(pos, xPos));
					pos = xPos + 1;
					ret = true;
				}
			}
			return ret;
		}

		/**
		 * Store the digits <code>n</code> in *n$ forms.
		 */
		private boolean setPrecisionArgPosition()
		{
			boolean ret = false;
			int xPos;
			for (xPos = pos; xPos < fmt.length(); xPos++)
			{
				if (!Character.isDigit(fmt.charAt(xPos)))
					break;
			}
			if (xPos > pos && xPos < fmt.length())
			{
				if (fmt.charAt(xPos) == '$')
				{
					positionalPrecision = true;
					argumentPositionForPrecision = Integer.parseInt(fmt
							.substring(pos, xPos));
					pos = xPos + 1;
					ret = true;
				}
			}
			return ret;
		}

		boolean isPositionalSpecification()
		{
			return positionalSpecification;
		}

		int getArgumentPosition()
		{
			return argumentPosition;
		}

		boolean isPositionalFieldWidth()
		{
			return positionalFieldWidth;
		}

		int getArgumentPositionForFieldWidth()
		{
			return argumentPositionForFieldWidth;
		}

		boolean isPositionalPrecision()
		{
			return positionalPrecision;
		}

		int getArgumentPositionForPrecision()
		{
			return argumentPositionForPrecision;
		}

		/**
		 * Set flag characters, one of '-+#0 or a space.
		 */
		private void setFlagCharacters()
		{
			/* '-+ #0 */
			thousands = false;
			leftJustify = false;
			leadingSign = false;
			leadingSpace = false;
			alternateForm = false;
			leadingZeros = false;
			for (; pos < fmt.length(); pos++)
			{
				char c = fmt.charAt(pos);
				if (c == '\'')
					thousands = true;
				else if (c == '-')
				{
					leftJustify = true;
					leadingZeros = false;
				}
				else if (c == '+')
				{
					leadingSign = true;
					leadingSpace = false;
				}
				else if (c == ' ')
				{
					if (!leadingSign)
						leadingSpace = true;
				}
				else if (c == '#')
					alternateForm = true;
				else if (c == '0')
				{
					if (!leftJustify)
						leadingZeros = true;
				}
				else
					break;
			}
		}

		/**
		 * The integer portion of the result of a decimal conversion (i, d, u,
		 * f, g, or G) will be formatted with thousands' grouping characters.
		 * For other conversions the flag is ignored.
		 */
		private boolean thousands = false;

		/**
		 * The result of the conversion will be left-justified within the field.
		 */
		private boolean leftJustify = false;

		/**
		 * The result of a signed conversion will always begin with a sign (+ or
		 * -).
		 */
		private boolean leadingSign = false;

		/**
		 * Flag indicating that left padding with spaces is specified.
		 */
		private boolean leadingSpace = false;

		/**
		 * For an o conversion, increase the precision to force the first digit
		 * of the result to be a zero. For x (or X) conversions, a non-zero
		 * result will have 0x (or 0X) prepended to it. For e, E, f, g, or G
		 * conversions, the result will always contain a radix character, even
		 * if no digits follow the point. For g and G conversions, trailing
		 * zeros will not be removed from the result.
		 */
		private boolean alternateForm = false;

		/**
		 * Flag indicating that left padding with zeroes is specified.
		 */
		private boolean leadingZeros = false;

		/**
		 * Flag indicating that the field width is *.
		 */
		private boolean variableFieldWidth = false;

		/**
		 * If the converted value has fewer bytes than the field width, it will
		 * be padded with spaces or zeroes.
		 */
		private int fieldWidth = 0;

		/**
		 * Flag indicating whether or not the field width has been set.
		 */
		private boolean fieldWidthSet = false;

		/**
		 * The minimum number of digits to appear for the d, i, o, u, x, or X
		 * conversions. The number of digits to appear after the radix character
		 * for the e, E, and f conversions. The maximum number of significant
		 * digits for the g and G conversions. The maximum number of bytes to be
		 * printed from a string in s and S conversions.
		 */
		private int precision = 0;

		/** Default precision. */
		private final static int defaultDigits = 6;

		/**
		 * Flag indicating that the precision is *.
		 */
		private boolean variablePrecision = false;

		/**
		 * Flag indicating whether or not the precision has been set.
		 */
		private boolean precisionSet = false;

		/*
  */
		private boolean positionalSpecification = false;

		private int argumentPosition = 0;

		private boolean positionalFieldWidth = false;

		private int argumentPositionForFieldWidth = 0;

		private boolean positionalPrecision = false;

		private int argumentPositionForPrecision = 0;

		/**
		 * Flag specifying that a following d, i, o, u, x, or X conversion
		 * character applies to a type short int.
		 */
		private boolean optionalh = false;

		/**
		 * Flag specifying that a following d, i, o, u, x, or X conversion
		 * character applies to a type lont int argument.
		 */
		private boolean optionall = false;

		/**
		 * Flag specifying that a following e, E, f, g, or G conversion
		 * character applies to a type double argument. This is a noop in Java.
		 */
		private boolean optionalL = false;

		/** Control string type. */
		private char conversionCharacter = '\0';

		/**
		 * Position within the control string. Used by the constructor.
		 */
		private int pos = 0;

		/** Literal or control format string. */
		private String fmt;
	}

	/** Vector of control strings and format literals. */

	private Vector vFmt = new Vector();

	/** Character position. Used by the constructor. */
	private int cPos = 0;

	/** Character position. Used by the constructor. */
	private DecimalFormatSymbols dfs = null;
}
